package com.wupaas.boot.core.business.oplog;

import com.wupaas.boot.core.business.context.ServletContextHolder;
import com.wupaas.boot.core.business.context.SpringContextHolder;
import com.wupaas.boot.core.business.oplog.format.IOplogFormat;
import com.wupaas.boot.core.business.security.jwt.JwtUtil;
import com.wupaas.boot.core.common.util.IpUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Date;

/**
 * @author JueYue
 * @date 2021-08-21-8-4
 * @since 1.0
 */
@Component
@Aspect
public class OpLogAspect {

    @Autowired
    private OplogService oplogService;

    @Resource(name = "baseOplogFormatService")
    private IOplogFormat formatService;

    @Pointcut(value = "@annotation(com.wupaas.boot.core.business.oplog.OpLog)")
    public void opLog() {

    }

    @Around(value = "opLog()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        HttpServletRequest request = ServletContextHolder.getRequest();
        OpLogModel log = new OpLogModel();
        log.setIp(getIp(request));
        log.setCreateTime(new Date());
        log.setUrl(request.getPathInfo());
        Object object;
        long starTime = System.nanoTime();
        try {
            object = point.proceed();
        } catch (Exception e) {
            log.setTakeTime(System.nanoTime() - starTime);
            log.setSucceed("2");
            oplogService.save(log);
            throw e;
        }
        handlerData(point, log);
        log.setTenantId(JwtUtil.getTenantId());
        log.setUserId(JwtUtil.getUserName());
        log.setTakeTime(System.nanoTime() - starTime);
        log.setSucceed("1");
        oplogService.save(log);
        return object;
    }

    private void handlerData(ProceedingJoinPoint joinPoint, OpLogModel log) throws ClassNotFoundException {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        log.setMethod(methodName);
        log.setClassName(targetName);

        Object[] arguments = joinPoint.getArgs();
        OpLog opLog = OplogReflect.fromClass(Class.forName(targetName)).getOplog(methodName + "_" + arguments.length);
        log.setType(opLog.type().name());

        log.setLogName(OplogReflect.fromClass(Class.forName(targetName)).getName());

        String[] argumentsNames = OplogReflect.fromClass(Class.forName(targetName)).getParam(methodName + "_" + arguments.length);
        log.setMessage(getMessageFormat(opLog.actionFormat()).format(opLog.action(), argumentsNames, arguments));
    }

    /**
     * 获取具体操作信息
     *
     * @param actionFormat
     * @return
     */
    private IOplogFormat getMessageFormat(String actionFormat) {
        IOplogFormat format = null;
        if (actionFormat.equals("baseOplogFormatService")) {
            format = formatService;
        } else {
            format = SpringContextHolder.getBean(actionFormat);
        }
        return format;
    }


    private String getIp(HttpServletRequest request) {
        String ip = IpUtil.getIpAddr(request);
        ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
        return ip;
    }

}
